// File: jmcomic-core/src/main/java/dev/jukomu/common/postman/proxy/RetryPostman.java
package dev.jukomu.common.postman.proxy;

import dev.jukomu.common.postman.Postman;
import dev.jukomu.common.util.net.IResponse;
import dev.jukomu.common.util.system.SystemUtils;

import java.util.Map;

/**
 * 对应Python的RetryPostman，一个Postman代理，用于重试请求。
 */
public class RetryPostman extends PostmanProxy {

    private final int retryTimes; // 重试次数

    /**
     * 构造函数。
     *
     * @param postman    被代理的Postman实例。
     * @param retryTimes 重试次数。
     */
    public RetryPostman(Postman postman, int retryTimes) {
        super(postman);
        if (retryTimes < 0) {
            throw new IllegalArgumentException("Retry times cannot be negative.");
        }
        this.retryTimes = retryTimes;
    }

    /**
     * 执行带重试机制的请求。
     *
     * @param requestFunction 执行实际请求的函数（例如Postman.get或Postman.post）
     * @param url             请求URL
     * @param kwargs          请求参数Map
     * @return 响应对象IResponse
     * @throws Exception 如果所有重试都失败，则抛出异常
     */
    protected IResponse retryRequest(RequestFunction requestFunction, String url, Map<String, Object> kwargs) throws Exception {
        if (retryTimes <= 0) {
            return requestFunction.execute(url, kwargs);
        }

        for (int i = 0; i < retryTimes; i++) {
            try {
                return requestFunction.execute(url, kwargs);
            } catch (InterruptedException e) {
                // 如果是中断异常，直接抛出，不重试
                throw e;
            } catch (Exception e) {
                excpHandle(e); // 处理异常
                tipRetrying(i, requestFunction, url, kwargs); // 提示重试
            }
        }

        return fallback(url, kwargs); // 所有重试都失败后的处理
    }

    @Override
    public IResponse get(String url, Map<String, Object> kwargs) throws Exception {
        // 使用Lambda表达式包装get方法
        return retryRequest((u, k) -> postman.get(u, k), url, kwargs);
    }

    @Override
    public IResponse post(String url, Map<String, Object> kwargs) throws Exception {
        // 使用Lambda表达式包装post方法
        return retryRequest((u, k) -> postman.post(u, k), url, kwargs);
    }

    @Override
    public Postman copy() {
        return new RetryPostman(postman.copy(), retryTimes);
    }

    /**
     * 定义一个函数式接口来表示请求方法。
     */
    @FunctionalInterface
    protected interface RequestFunction {
        IResponse execute(String url, Map<String, Object> kwargs) throws Exception;
    }

    /**
     * 当所有重试都失败时的回退处理。
     *
     * @param url    请求URL
     * @param kwargs 请求参数Map
     * @return 响应对象IResponse (如果可以从回退中恢复)
     * @throws Exception 抛出异常表明请求最终失败
     */
    protected IResponse fallback(String url, Map<String, Object> kwargs) throws Exception {
        throw new Exception(
                String.format("Request failed after %d retries: URL=[%s], Parameters=[%s]", retryTimes, url, kwargs)
        );
    }

    /**
     * 异常处理钩子。
     * 默认打印堆栈信息。
     *
     * @param e 发生的异常
     */
    protected void excpHandle(Exception e) {
        SystemUtils.printStackTrace(); // 打印堆栈信息
    }

    /**
     * 重试时的提示信息。
     * 默认空实现，子类可覆盖。
     *
     * @param time            当前重试次数（从0开始）
     * @param requestFunction 请求函数
     * @param url             请求URL
     * @param kwargs          请求参数Map
     */
    protected void tipRetrying(int time, RequestFunction requestFunction, String url, Map<String, Object> kwargs) {
        // Default empty implementation
    }
}